import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';

import { ElMessage } from 'element-plus';
import NProgress from 'nprogress';
import usePermission from '@/store/usePermission';
import useGlobalData from '@/store/useGlobalData';

// 数据返回的接口
// 定义请求响应参数，不含data
interface Result {
    code: number;
    msg: string;
}

// 请求响应参数，包含data
interface ResultData<T = any> extends Result {
    data?: T;
}

enum ReQuestEnums {
    TIMEOUT = 60000, // 请求等待响应时间
    OVERDUE = 1103, // 登录失效
    SUCCESS = 10000, // 请求成功
}

// 网络请求地址
export const baseURL: string = import.meta.env.VITE_HOST;

const config = {
    // 默认地址
    baseURL: baseURL as string,
    // 设置超时时间
    timeout: ReQuestEnums.TIMEOUT as number,
    // 跨域时候允许携带凭证
    // withCredentials: true,
};

class Request {
    // 定义成员变量并指定类型
    service: AxiosInstance;

    public constructor(config: AxiosRequestConfig) {
        this.service = axios.create(config);
        /**
         * 请求拦截器
         * 客户端发送请求 -> [请求拦截器] -> 服务器
         * token校验(JWT) : 接受服务器返回的token,存储到vuex/pinia/本地储存当中
         */
        this.service.interceptors.request.use(
            (config: AxiosRequestConfig) => {
                NProgress.start();
                const permission = usePermission();
                const globalData = useGlobalData();
                if (permission.token) {
                    config.headers = {
                        Authorization: permission.token,
                        menuId: globalData.menuId,
                    };
                }
                return config;
            },
            (error: AxiosError) => {
                NProgress.done();
                return Promise.reject(error);
            }
        );
        /**
         * 响应拦截器
         * 服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
         */
        this.service.interceptors.response.use(
            (response: AxiosResponse) => {
                const { data, request } = response;
                const permission = usePermission();
                NProgress.done();
                // 登录信息失效，应跳转到登录页面，并清空本地的token
                if (data.code === ReQuestEnums.OVERDUE) {
                    permission.setToken(null);
                    permission.setMenuList([]);
                    window.location.reload();
                    return Promise.reject(data);
                }
                // 全局错误信息拦截（防止下载文件得时候返回数据流，没有code，直接报错）
                if (data.code && data.code !== ReQuestEnums.SUCCESS) {
                    ElMessage.error(data.msg);
                    return Promise.reject(data);
                }
                // 当是下载接口的时候返回所有接口信息
                if (request.responseType === 'blob') {
                    return response;
                }
                return data;
            },
            (error: AxiosError) => {
                NProgress.done();
                const { response } = error;
                if (response) {
                    const data = response.data as any;
                    ElMessage.error(data.msg || '服务器异常！');
                }
                if (!window.navigator.onLine) {
                    ElMessage.error('网络连接失败!');
                }
                return Promise.reject(error);
            }
        );
    }

    // 常用方法封装get请求
    get(url: string, params?: object): Promise<ResultData<any>> {
        return this.service.get(url, { params });
    }

    // 常用方法封装post请求
    post(url: string, data?: object): Promise<ResultData<any>> {
        return this.service.post(url, data);
    }

    // 文件下载
    download(url: string, data?: any) {
        return this.service({
            url,
            method: 'post',
            responseType: 'blob',
            data,
        });
    }
}

export default new Request(config);
